package fishBids.group3.behaviour.bidder;

import java.util.Date;

import jade.content.Concept;
import jade.content.ContentElement;
import jade.content.onto.basic.Action;
import jade.core.AID;
import jade.core.behaviours.CyclicBehaviour;
import jade.core.behaviours.SequentialBehaviour;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.tools.logging.ontology.GetAllLoggers;
import es.upm.agents.ontology.Product;
import es.upm.agents.ontology.ToBid;
import es.upm.agents.ontology.ToGetPrice;
import es.upm.agents.ontology.ToGetPriceResponse;
import es.upm.agents.ontology.ToItemCancelled;
import es.upm.agents.ontology.ToNotifyWinner;
import es.upm.agents.ontology.ToVariatePrice;
import fishBids.group3.Bidder3;
import fishBids.group3.behaviour.GetAmountBehaviour;
import fishBids.group3.behaviour.GetMoneyBehaviour;
import fishBids.group3.behaviour.GetPriceBehaviour;
import fishBids.group3.common.Constants;
import fishBids.group3.utils.Utils;

public class PriceVariatedBidderBehaviour extends CyclicBehaviour {

	/**
	 * 
	 */
	private static final long serialVersionUID = -284773764555908942L;
	
	public PriceVariatedBidderBehaviour(Bidder3 agBidder,AID marketID, AID bankID){
		super(agBidder);
		this.agBidder = agBidder;
		this.marketID = marketID;
		this.bankID = bankID;
	}

	@Override
	public void action() {
		
		//Receive PriceVariated message
		MessageTemplate mt1 = MessageTemplate.and( 
	    	MessageTemplate.MatchLanguage(this.agBidder.getCodec().getName()), 
	    	MessageTemplate.and(MessageTemplate.MatchOntology(this.agBidder.getOntology().getName()),
	    	MessageTemplate.and(MessageTemplate.MatchProtocol(Constants.PRICE_VARIATED),
	    	MessageTemplate.MatchPerformative(ACLMessage.INFORM)))); 
	
		ACLMessage msg = this.agBidder.receive(mt1); 
		
		if (msg != null) {
			PVcounter++;
			ToVariatePrice toVariatePrice = (ToVariatePrice) Utils.extractContent(this.agBidder,msg);
//			System.out.println("Bidder>>>>> price variated with price " + toVariatePrice.getProduct().getPrice());
			if (!auctionStart){				
				oldProduct.setProductType(Constants.CALAMARI_TYPE);
				oldProduct.setAmount(0);
				auctionStart = true;
			}
			
			//if the new message is a different product, start again the strategy
			if (ItemCancel || NotifyWinner) {
				//System.out.println("Bidder>>>>> start new round of bidding");
				ItemCancel = false;
				NotifyWinner = false;
				oldProduct = toVariatePrice.getProduct();
				while (marketPrice == 0 ) {
					ToGetPrice toGetPrice = new ToGetPrice();
					toGetPrice.setProductType(toVariatePrice.getProduct().getProductType());
					marketPrice = getPriceBehaviour(toGetPrice, marketID);
			}
				PVcounter = 1;
				biddingPrice = marketPrice/100*75*toVariatePrice.getProduct().getAmount();
//				System.out.println("Bidder>>>>> bidding Price: " + biddingPrice);
			}
			//Sending BID
			if ((PVcounter >= 5) || ( biddingPrice >= toVariatePrice.getProduct().getPrice() )) {
				ToBid toBid = new ToBid();
				toBid.setProduct(toVariatePrice.getProduct());
				
				Utils.sendMessageWithConcept(ACLMessage.INFORM, 
						this.agBidder.getCodec(), 
						this.agBidder.getOntology(), 
						this.agBidder.getAuctioneerID(), 
						Constants.BID, 
						this.agBidder,
						toBid);
				System.out.println("Bidder3: buy");
			}
	
		}else{
			block();
		}
		//Wait for notify
		MessageTemplate mt2 = MessageTemplate.and( 
			MessageTemplate.MatchLanguage(this.agBidder.getCodec().getName()), 
			MessageTemplate.and(MessageTemplate.MatchOntology(this.agBidder.getOntology().getName()),
			MessageTemplate.and(MessageTemplate.MatchProtocol(Constants.NOTIFY_WINNERS),
			MessageTemplate.MatchPerformative(ACLMessage.INFORM)))); 
			
		ACLMessage msg2 = this.agBidder.receive(mt2); 
				
		if (msg2 != null) {
			NotifyWinner = true;
			toNotifyWinner = (ToNotifyWinner) Utils.extractContent(this.agBidder,msg2);
//			System.out.println("Bidder >>>>> received NOTIFYWINNER: " + toNotifyWinner.getWinner().getName() + " for product: " 
//					+ toNotifyWinner.getProduct().getProductType().getType() + ", amt:" +toNotifyWinner.getProduct().getAmount() + ", price: " + toNotifyWinner.getProduct().getPrice());
			SequentialBehaviour AfterBidProcess = new SequentialBehaviour();			
			AfterBidProcess.addSubBehaviour(new GetPriceBehaviour(this.agBidder,this.agBidder.getCodec(), this.agBidder.getOntology(),this.marketID, toNotifyWinner.getProduct().getProductType()) );
			AfterBidProcess.addSubBehaviour(new GetAmountBehaviour(this.agBidder,this.agBidder.getCodec(), this.agBidder.getOntology(),this.bankID));
			AfterBidProcess.addSubBehaviour(new SellProductBidderBehaviour(this.agBidder.getCodec(),this.agBidder.getOntology(),this.bankID,this.myAgent, toNotifyWinner.getProduct()));
			AfterBidProcess.addSubBehaviour(new GetMoneyBehaviour(this.agBidder,this.agBidder.getCodec(),this.agBidder.getOntology(),this.bankID) );
			
			if ((toNotifyWinner.getWinner().equals(this.agBidder.getAID())) && ((new Date()).getTime() - startingElapseTime.getTime() >= 5000)){
				myAgent.addBehaviour(AfterBidProcess);
			}
			return;	
		}
		
		//Wait for itemcancelled
		MessageTemplate mt3 = MessageTemplate.and( 
			MessageTemplate.MatchLanguage(this.agBidder.getCodec().getName()), 
			MessageTemplate.and(MessageTemplate.MatchOntology(this.agBidder.getOntology().getName()),
			MessageTemplate.and(MessageTemplate.MatchProtocol(Constants.ITEM_CANCELLED),
			MessageTemplate.MatchPerformative(ACLMessage.INFORM)))); 
					
		ACLMessage msg3 = this.agBidder.receive(mt3); 
						
		if (msg3 != null) {
			ItemCancel  = true;
			ToItemCancelled toItemCancelled = (ToItemCancelled) Utils.extractContent(this.agBidder,msg3);
//			System.out.println("Bidder >>>>> received ITEMCANCELLED: for product: " + toItemCancelled.getProduct().getProductType().getType() + ", amt:" + toItemCancelled.getProduct().getAmount() + ", price: " + toItemCancelled.getProduct().getPrice());
			return;	
		}
		
	}

	public float getPriceBehaviour(ToGetPrice toGetPrice, AID market){
		float marketprice = 0;
		if(status == 0){
	
			Utils.sendMessageWithConcept(ACLMessage.QUERY_REF, this.agBidder.getCodec(), this.agBidder.getOntology(), market, Constants.GET_PRICE, this.agBidder, toGetPrice);
	
			// Waits for the arrival of an answer
			//System.out.println("Auctioneer>> Sent GetPrice msg. Waiting for an INFORM or REFUSE message");
			status = 1;
		}
		// Receive the message
		ACLMessage msg = this.agBidder.receive(MessageTemplate.MatchProtocol(Constants.GET_PRICE)); 
		
		if(msg != null ){

			try {
				ContentElement ce = null;
				if (msg.getPerformative() == ACLMessage.INFORM) {
					//System.out.println("Auctionneer>>> received INFORM message arrived from Market");
					ce = this.agBidder.getContentManager().extractContent(msg);
					if (ce instanceof Action) {
						Action ac = (Action) ce;
						Concept cpt = ac.getAction();
						if (cpt instanceof ToGetPriceResponse) {
							ToGetPriceResponse toGetPriceResponse = (ToGetPriceResponse) cpt;
							marketprice = toGetPriceResponse.getPrice();
//							//System.out.println(this.auctioneerAg.getName()
//									+ " receive GetPrice of type: "
//									+ toGetPriceResponse.getProductType().getType() + " with price: "
//									+ toGetPriceResponse.getPrice());
						}
					}
					return marketprice;
				}
				if (msg.getPerformative() == ACLMessage.NOT_UNDERSTOOD) {
//					System.out.println(this.agBidder.getName()
//							+ " got a NOT_UNDERSTOOD in getPrice, check!!!!! :(");
					return 0;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		
		}
			return 0;


	}
	float biddingPrice;
	boolean finished = false;
	Bidder3 agBidder;
	Product oldProduct = new Product();
	boolean auctionStart = false;
	boolean ItemCancel = true;
	boolean NotifyWinner = true;
	int PVcounter = 0;
	float marketPrice;
	AID marketID;
	AID bankID;
	int status = 0;
	final Date startingElapseTime = new Date();
	ToNotifyWinner toNotifyWinner =  new ToNotifyWinner();
	

}
